package zhoug.zui.chart.pie;

import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.animation.LinearInterpolator;

import zhoug.logging.Logger;
import zhoug.common.utils.MathUtils;
import zhoug.zui.chart.IMarker;
import zhoug.zui.chart.ZUIChart;

import java.util.List;

/**
 * @Author 35574
 * @Date 2021/1/29
 * @Description
 */
public class ZUIPieChartView extends ZUIChart {
    private static final String TAG = ">>>ZUIPieChartView";
    private static final boolean DEBUG = false;

    private IMarker mMarker;
    private float mRadius;
    private List<PieEntry> mEntries;//数据集合
    private float mTotalValue;//数据对应的占比
    private int[] mColors=new int[]{0xffffcc00,0xffffccff,0xff99ff33,0xffff3333,0xff9933cc,0xff6666cc,0xff00cc33};//数据对应的颜色集合
    private Paint mPaint;
    private RectF mContentRect = new RectF();
    private float mHoleRate = 0.4f;//中间孔洞占半径的比率,为0是不画中间的孔洞
    private float mMinStrokeWidthRate = 0.5f;//根据数据大小,半径阶梯递减时的最小宽度和最大宽度的比率
    private GestureDetector mGestureDetector;


    public ZUIPieChartView(Context context) {
        this(context, null);
    }

    public ZUIPieChartView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ZUIPieChartView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

     /*   setEntries(Arrays.asList(
                new PieEntry(100,"label1"),
                new PieEntry(100,"label2"),
                new PieEntry(100,"label3")
                ));*/
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setAntiAlias(true);

        mGestureDetector = new GestureDetector(context, onGestureListener);
    }


  /*  @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawData(canvas);

    }*/

    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        if(mEntries!=null){
            calculateOffset();
            drawData(canvas);
            if (mAnim == null || !mAnim.isRunning()) {
                drawMarkers(canvas);
            }
        }



        //画饼图所在的圆
//        mPaint.setColor(Color.BLACK);
//        mPaint.setStrokeWidth(3);
//        mPaint.setStyle(Paint.Style.STROKE);
//        canvas.drawArc(mContentRect, 0, 360, false, mPaint);
//        canvas.drawCircle((mContentRect.left+mContentRect.right)/2,(mContentRect.top+mContentRect.bottom)/2,mRadius,mPaint);
    }

    /**
     * 饼图绘制区域
     */
    private RectF mPieRect = new RectF();
    private float animAngle = 360;
    private float stokeWidthPer = 0;
    private float mOffset=-1;//因为半径左键跌建,所以画出的图右边有一段空格

    private void drawData(Canvas canvas) {
        if (DEBUG) {
//            Logger.d(TAG, "drawData:");
        }
        if(mEntries==null){
            return;
        }
        float maxStrokeWidth = (1 - mHoleRate) * mRadius;
        float startAngle = 180;//开始角度
        float sweepAngle;
        mPaint.setStyle(Paint.Style.STROKE);
        float offset;
        float strokeWidth;
        float strokeWidthBan;
        for (int i = 0; i < mEntries.size(); i++) {
            float  rate = mEntries.get(i).getY() / mTotalValue;
            sweepAngle = rate * 180;
            mPaint.setColor(mColors[i % mColors.length]);
            offset = stokeWidthPer * i;
            strokeWidth = maxStrokeWidth - offset;
            strokeWidthBan = strokeWidth / 2;
            mPaint.setStrokeWidth(strokeWidth);

            mPieRect.left = mContentRect.left+mOffset + offset + strokeWidthBan;
            mPieRect.top = mContentRect.top + offset + strokeWidthBan;
            mPieRect.right = mContentRect.right+mOffset - offset - strokeWidthBan;
            mPieRect.bottom = mContentRect.bottom - offset - strokeWidthBan;
            if (startAngle >= animAngle) {
                break;
            }
            if (DEBUG) {
//                Logger.d(TAG, "drawData:startAngle=" + startAngle + ",animAngle" + animAngle);
            }
            float animSweepAngle = animAngle - startAngle;
            if (animSweepAngle > sweepAngle) {
                animSweepAngle = sweepAngle;
            }
            canvas.drawArc(mPieRect, startAngle, animSweepAngle, false, mPaint);
            startAngle += sweepAngle;
        }

    }

    /**
     * 计算偏移量
     */
    private void calculateOffset(){
        if(mOffset==-1){
            float maxStrokeWidth = (1 - mHoleRate) * mRadius;
            //每个数据图形递减的宽度
            stokeWidthPer = mEntries.size() == 1 ? 0 : (1 - mMinStrokeWidthRate) / (mEntries.size() - 1) * maxStrokeWidth;
            float maxArcX=0;
            float angle=180;
            float cx=(mContentRect.left+mContentRect.right)/2;
            for (int i = 0; i < mEntries.size(); i++) {
                float rate = mEntries.get(i).getY() / mTotalValue;
                angle+=rate*180;
                float arcXPoint = MathUtils.getArcXPoint(cx, mRadius - stokeWidthPer * i, angle);
                maxArcX=Math.max(maxArcX,arcXPoint);
                if (DEBUG) {
                    Logger.d(TAG, "calculateOffset:maxArcX="+maxArcX);
                }
            }
            mOffset=(getWidth()-maxArcX)/2;
            if(mOffset<0){
                mOffset=0 ;
            }
            if (DEBUG) {
                Logger.d(TAG, "calculateOffset:mOffset="+mOffset);
            }
        }
    }

    private void drawMarkers(Canvas canvas) {
        if (DEBUG) {
            Logger.d(TAG, "drawMarkers:");
        }
        if (mMarker != null && mHighlightIndex >= 0) {
            mMarker.refreshContent(mEntries.get(mHighlightIndex), mHighlightIndex);
            mMarker.draw(canvas, mMarkerX, mMarkerY);
        }
    }

    @Override
    public boolean isValuesToHighlight() {
        return mHighlightIndex >= 0;
    }

    @Override
    public void setHighlightIndex(int index) {
        mHighlightIndex = index;
    }


    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int radius = 0;
        if (widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY) {
            setMeasuredDimension(widthSize, heightSize);
        } else if (widthMode == MeasureSpec.EXACTLY) {
            radius = (widthSize - getPaddingStart() - getPaddingEnd()) / 2;
            if (heightSize > 0) {
                int maxRadius = heightSize - getPaddingTop() - getPaddingBottom();
                radius = Math.min(radius, maxRadius);
            }
            setMeasuredDimension(widthSize, radius + getPaddingTop() + getPaddingBottom());
        } else if (heightMode == MeasureSpec.EXACTLY) {
            radius = heightSize - getPaddingTop() - getPaddingBottom();
            if (widthSize > 0) {
                int maxRadius = (widthSize - getPaddingStart() - getPaddingEnd()) / 2;
                radius = Math.min(maxRadius, radius);
            }
            setMeasuredDimension(radius * 2 + getPaddingStart() + getPaddingEnd(), heightSize);

        } else {
            radius = Math.min((widthSize - getPaddingStart() - getPaddingEnd()) / 2, heightSize - getPaddingTop() - getPaddingBottom());
            setMeasuredDimension(radius * 2 + getPaddingStart() + getPaddingEnd(), radius + getPaddingTop() + getPaddingBottom());
        }

    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mRadius = Math.min((w - getPaddingStart() - getPaddingEnd()) / 2, h - getPaddingTop() - getPaddingBottom());

        float remainderW = (w - getPaddingStart() - getPaddingEnd() - mRadius*2) / 2;
        if (remainderW < 0) {
            remainderW = 0;
        }
        float remainderH = (h - getPaddingTop() - getPaddingBottom() - mRadius) / 2;
        if (remainderH < 0) {
            remainderH = 0;
        }
        mContentRect.left = getPaddingStart()+remainderW;
        mContentRect.top = getPaddingTop() + remainderH;
        mContentRect.right =  mContentRect.left + mRadius*2;
        mContentRect.bottom = mContentRect.top + mRadius * 2;
        if (DEBUG) {
            Logger.d(TAG, "onSizeChanged:mContentRect=" + mContentRect);
        }

       /* if(mEntries==null){
            return;
        }
        float maxStrokeWidth = (1 - mHoleRate) * mRadius;
        //每个数据图形递减的宽度
        stokeWidthPer = mEntries.size() == 1 ? 0 : (1 - mMinStrokeWidthRate) / (mEntries.size() - 1) * maxStrokeWidth;
        float maxArcX=0;
        float angle=180;
        float cx=(mContentRect.left+mContentRect.right)/2;
        for (int i = 0; i < mEntries.size(); i++) {
            float rate = mEntries.get(i).getY() / mTotalValue;
            angle+=rate*180;

            float arcXPoint = MathUtils.getArcXPoint(cx, mRadius - stokeWidthPer * i, angle);
            maxArcX=Math.max(maxArcX,arcXPoint);
            if (DEBUG) {
                Logger.d(TAG, "onSizeChanged:"+i+":"+maxArcX);
            }
        }
        mSpace=w-maxArcX;
        if(mSpace<0){
            mSpace=0 ;
        }
        mContentRect.left+=mSpace/2;
        mContentRect.right+=mSpace/2;
        if (DEBUG) {
            Logger.d(TAG, "onSizeChanged:mSpace="+mSpace);
        }*/
    }

    public void setMarker(IMarker marker) {
        this.mMarker = marker;
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);
        boolean b = mGestureDetector.onTouchEvent(event);

        return true;
    }

    private int mHighlightIndex = -1;//高亮数据的下标
    private float mMarkerX;
    private float mMarkerY;
    private GestureDetector.OnGestureListener onGestureListener = new GestureDetector.SimpleOnGestureListener() {
        @Override
        public boolean onSingleTapConfirmed(MotionEvent e) {
            float x = e.getX();
            float y = e.getY();
            float cX = (mContentRect.left+mOffset*2 + mContentRect.right) / 2;
            float cY = (mContentRect.top + mContentRect.bottom) / 2;
            if (DEBUG) {
//                Logger.d(TAG, "onSingleTapConfirmed:cX=" + cX + ",cY=" + cY);
//                Logger.d(TAG, "onSingleTapConfirmed:x=" + x + ",y=" + y);
            }
            float disX = x - cX;
            float disY = y - cY;
            float dis = (float) Math.sqrt(disX * disX + disY * disY);


            if (DEBUG) {
//                Logger.d(TAG, "onSingleTapConfirmed:mRadius=" + mRadius + ",dis=" + dis);
            }
            int clickIndex = -1;
            if (dis <= mRadius && dis>mHoleRate*mRadius) {
                if (DEBUG) {
                    Logger.d(TAG, "onSingleTapConfirmed:点击图形");
                }
                double angle = MathUtils.getAngle(disX, disY);
                if (DEBUG) {
                    Logger.d(TAG, "onSingleTapConfirmed:angle=" + angle);
                }
                float rate;
                float startAngle = 180;
                float endAngle = 180;
                for (int i = 0; i < mEntries.size(); i++) {
                    rate = mEntries.get(i).getY() / mTotalValue;
                    mPaint.setColor(mColors[i % mColors.length]);
                    endAngle += rate * 180;
                    if (DEBUG) {
//                        Logger.d(TAG, "onSingleTapConfirmed:startAngle=" + startAngle + ",endAngle=" + endAngle);
                    }
                    if (angle > startAngle && angle < endAngle) {
                        clickIndex = i;
                        if (DEBUG) {
//                            Logger.d(TAG, "onSingleTapConfirmed:clickIndex=" + clickIndex);
                        }
                        break;
                    }
                    startAngle = endAngle;
                }
            }

            if (clickIndex != -1) {
                if (mHighlightIndex == clickIndex) {
                    mHighlightIndex = -1;
                } else {
                    mHighlightIndex = clickIndex;
                }
            } else {
                mHighlightIndex = -1;
            }
            mMarkerX = x;
            mMarkerY = y;
            postInvalidate();
            return true;
        }
    };


    private ValueAnimator mAnim;

    public void startAnim(int during) {
        if (mAnim != null && mAnim.isRunning()) {
            mAnim.cancel();
        }
        animAngle = 180;
        mAnim = ValueAnimator.ofFloat(180, 360);
        mAnim.setDuration(during);
        mAnim.setInterpolator(new LinearInterpolator());
        mAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                animAngle = (float) animation.getAnimatedValue();
                if (DEBUG) {
//                    Logger.d(TAG, "onAnimationUpdate:animAngle=" + animAngle);
                }
                postInvalidate();
            }
        });
        mAnim.start();
    }





    public float getTotalValue() {
        return mTotalValue;
    }


    public int[] getColors() {
        return mColors;
    }

    public void setColors(int[] colors) {
        this.mColors = colors;
    }

    public void setHoleRate(float holeRate) {
        this.mHoleRate = holeRate;
    }

    public void setMinStrokeWidthRate(float minStrokeWidthRate) {
        this.mMinStrokeWidthRate = minStrokeWidthRate;
    }

    public void setEntries(List<PieEntry> entries) {
        this.mEntries = entries;
        mTotalValue = 0;
        mOffset=-1;
        if (entries != null && entries.size() > 0) {
            for (int i = 0; i < entries.size(); i++) {
                mTotalValue += entries.get(i).getY();
            }
        }
    }

    public List<PieEntry> getEntries() {
        return mEntries;
    }

}
